手写(复制粘贴)Promise
手写一个符合 Promise/A+ 规范的 Promise ,需要理解其核心机制:状态管理、异步回调、链式调用、错误传递。
以下代码完全自(ctrl)主(c)研(腾讯)发(元宝)
全码
/\*\*
- 辅助函数:处理 Promise 解析逻辑(Promise/A+ 规范核心)
-
- @params promise2
- @params returnValue 返回值
- @params resolve 完成方法
- @params reject 拒绝方法
- \*/
function resolvePromise(promise2, returnValue, resolve, reject) {
// 1. 防止循环引用(如 promise2.then 返回 promise2 自己)
if (promise2 === returnValue) {
return reject(new TypeError('检测到 Promise 的循环链'));
}
// 2. 如果 returnValue 是 MyPromise 实例,递归解析
if (returnValue instanceof MyPromise) {
returnValue.then(
_result => resolvePromise(promise2, _result, resolve, reject),
err => reject(err)
);
return;
}
// 3. 如果 returnValue 是对象/函数,尝试获取 then 方法(处理 thenable 对象)
let then;
try {
then = returnValue?.then;
} catch (err) {
return reject(err); // 获取 then 失败,直接 reject
}
// 4. 如果 then 是函数,当作 “thenable” 对象处理
if (typeof then === 'function') {
// 防止多次调用 resolve/reject
let called = false;
try {
then.call(
returnValue,
_result => {
if (called) return;
called = true;
resolvePromise(promise2, _result, resolve, reject); // 递归解析 _result
},
err => {
if (called) return;
called = true;
reject(err); // 调用 onRejected,传递错误
}
);
} catch (err) {
if (called) return;
reject(err); // 调用 then 失败,reject
}
} else {
// 5. 如果 returnValue 是普通值(非对象/函数/thenable),直接 resolve
resolve(returnValue);
}
}
// 自定义 Promise 类
class MyPromise {
// 状态:pending/fulfilled/rejected(不可逆)
state = 'pending';
// 成功值
value = undefined;
// 失败原因
reason = undefined;
// 存储 pending 状态下的回调(解决同步 resolve 时 then 未注册的问题)
onFulfilledCallbacks = [];
onRejectedCallbacks = [];
// 初始化
constructor(executor) {
// executor 是用户传入的函数,接收 resolve/reject
const resolve = (value) => {
// 状态已改变,跳过
if (this.state !== 'pending') return;
this.state = 'fulfilled';
this.value = value;
// 执行所有 pending 状态下的 fulfilled 回调(异步)
this.onFulfilledCallbacks.forEach(cb => cb());
};
const reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(cb => cb());
};
try {
executor(resolve, reject); // 执行用户逻辑
} catch (err) {
reject(err); // executor出错,直接reject
}
}
// then 方法:注册 fulfilled/rejected 回调,返回新 Promise(链式调用)
then(onFulfilled, onRejected) {
// 返回新 Promise,确保链式调用
const promise2 = new MyPromise((resolve, reject) => {
// 处理 fulfilled 状态的回调
const handleFulfilled = () => {
queueMicrotask(() => { // 异步执行(模拟微任务)
try {
if (typeof onFulfilled === 'function') {
// 调用用户回调
const returnValue = onFulfilled(this.value);
// 处理返回值
resolvePromise(promise2, returnValue, resolve, reject);
} else {
resolve(this.value); // 未传 onFulfilled,直接传递值
}
} catch (err) {
reject(err); // 回调出错,reject 新 Promise
}
});
};
// 处理rejected状态的回调
const handleRejected = () => {
queueMicrotask(() => {
try {
if (typeof onRejected === 'function') {
// 调用用户回调
const returnValue = onRejected(this.reason);
resolvePromise(promise2, returnValue, resolve, reject);
} else {
// 未传onRejected,直接传递错误
reject(this.reason);
}
} catch (err) {
reject(err);
}
});
};
// 根据当前状态执行回调
if (this.state === 'fulfilled') {
handleFulfilled();
} else if (this.state === 'rejected') {
handleRejected();
} else {
// pending状态,存储回调等待resolve/reject
this.onFulfilledCallbacks.push(handleFulfilled);
this.onRejectedCallbacks.push(handleRejected);
}
});
return promise2;
}
// catch 方法:语法糖,仅处理 rejected
catch(onRejected) {
return this.then(null, onRejected);
}
// 静态方法:创建已 resolve 的 Promise
static resolve(value) {
return new MyPromise(resolve => resolve(value));
}
// 静态方法:创建已 reject 的 Promise
static reject(reason) {
return new MyPromise((\_, reject) => reject(reason));
}
}
状态管理
Promise 有三种状态:
pending:初始状态,等待异步操作完成fulfilled:异步操作成功,储存结果valuerejected:异步操作失败,储存原因reason
状态改变仅能从 pending → fulfilled 或 pending → rejected,且不可回退
异步处理
- 储存回调:当
promise处于pending状态时,then注册的回调会被储存入onFulfilledCallbacks/onRejectedCallbacks数组,等待resolve/rejected触发 - 异步执行:使用
queueMicrotask(模拟微任务) 确保 then 的回调异步执行,符合 Promise/A+ 规范
链式调用
then 方法返回新的 Promise,实现链式调用。新的 Promise 的状态由 then 回调的返回值决定:
- 如果回调返回普通值:
promise2直接 resolve 该值 - 如果回调返回
Promise:promise2的状态由返回的Promise决定(递归解析) - 如果回调抛出错误:
promise2直接reject该错误
错误的调用
- Executor 错误:执行用户传入的
executor时出错,直接reject - Then 回调错误:
then注册的回调错误,错误会传递给下一个then的onRejected或catch
resolvePromise 函数
处理 then 回调返回值 returnValue 的所有可能情况:
- 循环引用检测:防止
promise2.then返回promise2自身,导致无限递归 - Promise 实例:递归解析返回的
Promise,直到其状态改变 - Thenable 对象:尝试调用
then方法,递归解析其结果(兼容原生Promise的thenable) - 普通值:直接
resolve该值
注意事项
- 异步性:
then的回调始终异步执行,即使resolve是同步调用的 - 状态不可逆:一旦状态更改,无法回退
- 错误捕获:所有的错误(
executor、then回调)都需要通过reject传递,最终由catch捕获 - 链式调用:
then返回新的Promise,确保后续的回调能处理前序结果 - 循环引用:
resolvePromise中需检测promise2 === returnValue,避免无限递归
执行解析(我没看懂源码,继续追问的元宝)
使用一段实例代码追问的解析:
new MyPromise((resolve, reject) => {
setTimeout(() => {
console.log('决议前');
resolve(true); // 触发Promise状态变更
console.log('决议后');
}, 100);
}).then(res => {
console.log(res); // 为何在“决议后”之后执行?
});
初始化 Promise,注册 then 回调
执行 new MyPromise(executor) , 传入的 executor 立即执行:
- 遇到
setTimeout,将其回调(宏任务)放入宏任务列队,等待执行 then方法被调用,返回新的Promise,但当前的Promise状态还是pending,因此then的两个回调 (onFulfilled、onRejected)被暂存到onFulfilledCallbacks数组中
宏任务(setTimeout 回调)执行
100 ms 后,setTimeout 的回调执行触发(宏任务开始执行)
- 打印
"决议前" - 调用
resolve(true)Promise状态从pending变化为fulfilled- 执行
onFulfilledCallbacks数组中的回调(即handleFulfilled函数)
- 打印
"决议后"
handleFulfilled 触发微任务调度
handleFulfilled 是手写 Promise 中定义的回调函数,内部使用 queueMicrotask 包裹了真正的处理逻辑
const handleFulfilled = () => {
queueMicrotask(() => {
// 关键:将逻辑包装成微任务
try {
if (typeof onFulfilled === 'function') {
const returnValue = onFulfilled(this.value); // 调用 then 的回调(打印 res)
resolvePromise(promise2, returnValue, resolve, reject);
} else {
resolve(this.value);
}
} catch (err) {
reject(err);
}
});
};
resolve(true) 被调用时, handleFulfilled 被同步执行,但它的内部的 queueMicrotask 会将真正的 then 回调逻辑放入微任务列队
宏任务结束,执行微任务
setTimeout 的宏任务执行完毕,事件循环开始清空微任务列队:
- 执行
queueMicrotask中的回调,即调用onFulfilled(res)(res值为true) - 打印
true